perm filename ALARM.MAC[AL,HE] blob sn#744183 filedate 1984-02-23 generic text, type C, neo UTF8
COMMENT āŠ—   VALID 00007 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00002 00002	Low-level routines for AL-ARM communication using the ethernet via pups
C00005 00003	Local data
C00007 00004	function initEther(var abortf: boolean): integer
C00009 00005	procedure openConnection
C00012 00006	alMessage & readPup
C00022 00007	Aux routins: SETOPUP & SNDPUP
C00025 ENDMK
CāŠ—;
;Low-level routines for AL-ARM communication using the ethernet via pups

        .TITLE  ALARM

	.DSABL	GBL

	.MCALL	QIOW$S,QIO$S,ALUN$S,SETF$S,CLEF$S,WTSE$S,RDAF$S
	.MCALL	MRKT$S,CMKT$S
	.GLOBL	IO.KIL
	.GLOBL	IO.WLB
	.GLOBL	IO.RLB

	.GLOBL	$B72
			;$B72 = DISPOSE label in PASCAL runtime system

;MISCELLANEOUS CONSTANTS

ENOUT	= 8.		;Ethernet output channel
ENIN	= 9.		;Ethernet input channel

ENEV1	= 9.		;Input event flags for receiving pup packets
ENEV2	= 10.
ENEVF1	= 000400	;Masks for both input event flags
ENEVF2	= 001000	;Masks for both input event flags

MSGSIZ	= 116		;AL-ARM message size

PUP	= 1000		;Pup packet identifier
PUPOV	= 22.
ALPSIZ	= PUPOV + MSGSIZ - 2	;Length of AL-ARM message
PUPSIZ	= 560.

SRC	= 0		;Packet's source
DEST	= 1		;Packet's destination
TYPE	= 2		;Packet type: 1000 = pup, 1001 = IP
LENGTH	= 4		;Packet length
PUPTYP	= 6		;Pup type
PUPCTL	= 7		;Transport control
PUPID	= 10		;Pup identification (2 words)
PUPID2	= 12
DSTHST	= 14		;Destination host
DSTNET	= 15		;Destination network
DSTSOC	= 16		;Destination socket (2 words)
DSTSC2	= 20
SRCHST	= 22		;Source host
SRCNET	= 23		;Source network
SRCSOC	= 24		;Source socket (2 words)
SRCSC2	= 26		;Source socket (2 words)
PDATA	= 30		;Start of data in pup

HELLOP	= 200		;Pup types for AL-ARM communication
ARMFRE	= 201
ARMBSY	= 202
THEREP	= 203
ALLIVE	= 204
ALARM 	= 205
ACK   	= 206
BYEBYE	= 207

ARMSOC	= 106		;ARM server socket

;Local data

INPUP1:	.BLKW	PUPSIZ		;For receiving pups
INPUP2:	.BLKW	PUPSIZ

OUTPUP:	.BLKW	PUPOV+MSGSIZ	;For sending ALARM messages to AL

ACKPUP:	.BLKW	PUPOV		;Just pup overhead - no data bytes

THRPUP:	.BLKW	PUPOV		;Just pup overhead - no data bytes

BSYPUP:	.BLKW	PUPOV		;Just pup overhead - no data bytes

;Information defining current connection

HSTNUM:	.BYTE	304,50		;Host number/net of server - set by initEther
CONHST:	.BYTE	0		;Connection host - address of AL
CONNET:	.BYTE	0		;Connection net
CONSOC:	.WORD	0		;Connection socket
CONSC2:	.WORD	0
CONDST:	.WORD	0		;Where we send pups to reach connection host

SEQIN:	.WORD	0		;Sequence number for input
SEQIN2:	.WORD	0
SEQOUT:	.WORD	0		;Sequence number for output
SEQOU2:	.WORD	0

TIMOUT:	.WORD	0		;Number of ticks that no messages passed
ACKTIM:	.WORD	0		;Number of ticks before retransmit
RETRY:	.WORD	0		;Number of times to retry transmission
IOACT:	.WORD	0		;Non-zero if any I/O activity this cycle
THEREC:	.WORD	0		;Waiting for AL alive reply
THERER:	.WORD	0

OUTLST:	.WORD	0		;Head of list of messages to send to AL

IOSB:	.BLKW	2

FLAGS:	.BLKW	4

ABORTF:	.WORD	0		;Address of ARM's abort flag

MESREC:	.WORD	0
INPMES:	.WORD	0

;function initEther(var abortf: boolean): integer;

;ARM should call initEther once during initialization.  The one parameter
;passed to initEther - abortf - will be set to TRUE (non-zero) whenever
;the AL-ARM connection is broken, i.e. AL sends a byebye packet or AL doesn't
;respond.  It will be set FALSE (zero) when a connection is established by
;the openConnection routine.  InitEther returns the ethernet number for the
;host machine.  This is 304 (octal) for the 11/45, Ubehebe, and 323 for the
;11/60, Pisgah.

	FUNC	INITETHER,HNUM,INTEGER
	PARAM	ABTF,ADDRESS
	SAVE	<R0,R1,R2>
	BEGIN

	ALUN$S	#ENOUT,#"EN,#0		;Assign LUN for output
	ALUN$S	#ENIN,#"EN,#1		;Assign LUN for input

	MOV	ABTF(SP),ABORTF		;Remember address of "abort" flag

	CLR	CONHST			;No connection open yet

;GET AND RETURN HOST ADDRESS
 
	QIO$S	#3000,#ENIN,,,#IOSB
	MOV	IOSB+2,HNUM(SP)		;HOST ADDRESS
	MOVB	IOSB+2,HSTNUM		;Save a copy for local use
	ENDPR

;procedure openConnection

;Waits for AL to open a connection before returning.
;Sets the abort flag to FALSE.

	PROC	OPENCONNECTION
	SAVE	<R0,R1,R2>
	BEGIN
	QIO$S	#IO.KIL,#ENIN		;Flush any pending pup reads

	;Now wait for someone to say hello to us
	;Accept any pup sent to ARM server socket from any host/socket

LOOP:	QIOW$S	#IO.RLB,#ENIN,#ENEV1,,,,<#INPUP1,#PUPSIZ,#ARMSOC,#0,#0,#0>

	CMPB	#HELLOP,INPUP1+PUPTYP	;Got one! Is it a HELLO packet?
	BNE	LOOP			; Nope - ignore it & wait for another
	MOV	INPUP1,CONDST		; Yes! - Get connection address
	SWAB	CONDST			;Net host who sent us pup (for gateways)
	MOV	INPUP1+SRCHST,CONHST	;Host/Net info
	MOV	INPUP1+SRCSOC,CONSOC	;Socket
	MOV	INPUP1+SRCSC2,CONSC2
	MOV	#ACKPUP,R1		;Send RFC back to establish connection
	JSR	PC,SETOPUP		;First set up address info
	MOVB	#ARMFRE,ACKPUP+PUPTYP	;Tell AL that ARM is free
	JSR	PC,SNDPUP		;Send reply out
	MOV	#SEQIN,R1
	MOV	#11.,R0
10$:	CLR	(R1)+			;Reset connection sequence numbers
	SOB	R0,10$			; & various timers
	CLRB	@ABORTF			;Tell ARM connection established

	;Enter two pup read requests & return to ARM

	QIO$S	#IO.RLB,#ENIN,#ENEV1,,,,<#INPUP1,#PUPSIZ,#ARMSOC,#0,#0,#0>
	QIO$S	#IO.RLB,#ENIN,#ENEV2,,,,<#INPUP2,#PUPSIZ,#ARMSOC,#0,#0,#0>

	ENDPR

;alMessage & readPup

;function alMessage(inp,outp: messagep; ticks: integer): boolean;

;ARM passes two messages: one pointing to a free record for any message from AL
;and one (possibly NIL) pointing to a message to send to AL.  If a message is
;received the function returns TRUE.  The third parameter is used to tell the
;routine how long it has been since the last time it was scheduled (in 60ths of
;a second).

	FUNC	ALMESSAGE,MESP,BOOLEAN
	PARAM	INP,ADDRESS
	PARAM	OUTP,ADDRESS
	PARAM	TICKS,INTEGER
	SAVE	<R0,R1,R2,R3>
	BEGIN
	MOV	INP(SP),INPMES		;Get AL-ARM message record
	CLRB	MESP(SP)		;Assume no message
	CLR	MESREC
	CLR	IOACT			;Assume nothing to do
	RDAF$S	#FLAGS			;See if any input to process
	BIT	#ENEVF1,FLAGS		;Pup 1 received?
	BEQ	1$			; No
	MOV	#INPUP1,R3		; Yes - see what it says
	JSR	PC,READPU
	MOVB	MESREC,MESP(SP)		;Maybe a message now
	QIO$S	#IO.RLB,#ENIN,#ENEV1,,,,<#INPUP1,#PUPSIZ,#ARMSOC,#0,#0,#0>

1$:	BIT	#ENEVF2,FLAGS		;How about pup 2?
	BEQ	OUTQ			; No - deal with output
	MOV	#INPUP2,R3		; Yes - see what it says
	JSR	PC,READPU
	MOVB	MESREC,MESP(SP)		;Maybe a message now
	QIO$S	#IO.RLB,#ENIN,#ENEV2,,,,<#INPUP2,#PUPSIZ,#ARMSOC,#0,#0,#0>

OUTQ:	TST	OUTP(SP)		;Any message for output?
	BEQ	55$			; No
	MOV	#OUTLST,R1		; Yes - add it to output list
52$:	TST	(R1)			;Last entry in queue?
	BEQ	53$			; Yes
	MOV	(R1),R1			; No - move down list
	BR	52$
53$:	MOV	OUTP(SP),(R1)		;Add it to end of list
	CLR	@(R1)			; & zero its NEXT pointer

55$:	TST	ACKTIM			;Are we waiting for an ACK?
	BEQ	60$			; No
	SUB	TICKS(SP),ACKTIM	; Yes - update timer
	BGT	DONE			;Still waiting - skip ahead	
	MOV	#1,R1			;*** ACK time-out error
	DEC	RETRY			;Retransmit?
	BLE	ALDEAD			; No - time-out
	MOV	#20.,ACKTIM		; Yes - reset timer
	BR	70$			;  & send pup out again

60$:	MOV	OUTLST,R3		;Get message to send (if any)
	BEQ	DONE			; Nothing to send
	MOV	#OUTPUP,R1
	JSR	PC,SETOPUP		;Set up address info
	MOVB	#ALARM,OUTPUP+PUPTYP	;ALARM message
	MOVB	#ALPSIZ,OUTPUP+LENGTH	;ALARM message length
	INC	SEQOU2			;Update output sequence number
	ADC	SEQOUT
	MOV	SEQOUT,OUTPUP+PUPID	; & stick it into pup id #
	MOV	SEQOU2,OUTPUP+PUPID2
	MOV	#OUTPUP+PDATA,R2	;Start of pup data area
	MOV	#MSGSIZ/2-1,R0		;Length of AL-ARM message in words
	ADD	#2,R3			;Skip over local next pointer
62$:	MOV	(R3)+,(R2)+		;Copy message into pup packet
	SOB	R0,62$
	MOV	OUTLST,R3		;Advance output queue
	MOV	(R3),OUTLST
	MOV	R3,-(SP)		; & flush old message
	MOV	#MSGSIZ,R0		;AL-ARM message size
	JSR	PC,$B72			;Call DISPOSE

	MOV	#6,ACKTIM		;Set timers (first time is shorter)
	MOV	#20.,RETRY
	
70$:	MOV	#OUTPUP,R1
	JSR	PC,SNDPUP		;Send message out to AL
	INC	IOACT			; & set i/o flag

DONE:	TST	IOACT			;Did we do anything?
	BEQ	90$			; No
	CLR	TIMOUT			; Yes - reset time out counter
	BR	FIN			;   & all done

90$:	TST	THEREC			;Are we awaiting an AL ALIVE reply?
	BEQ	98$			; No
	SUB	TICKS(SP),THEREC	; Yes - update timer
	BGT	FIN			;  & keep waiting
	MOV	#2,R1			;*** AL dead error
	DEC	THERER			;Time for retransmission?
	BLE	ALDEAD			; No - time-out, assume AL dead

97$:	MOV	#THRPUP,R1		;See if AL is still alive
	JSR	PC,SETOPUP		;Set up address info
	MOVB	#THEREP,THRPUP+PUPTYP	;Ask AL to say it's still there
	JSR	PC,SNDPUP		;Send reply out
	MOV	#600.,THEREC		;Reset timer
	BR	FIN

98$:	ADD	TICKS(SP),TIMOUT	;Nothing happening - update counter
	CMP	#3600.,TIMOUT		;Has it been one minute yet?
	BGT	FIN			; No
	MOV	#6,THERER		; Yes - see if AL is still alive
	BR	97$			;(send 6 queries - one every 10 secs)

ALDEAD:	MOV	R1,@ABORTF		;*** Tell ARM to go into wait state
;;;	INCB	@ABORTF			;Tell ARM to go into wait state
	MOV	OUTLST,R3		;Time-out, assume AL dead
1$:	TST	R3			;Any output messages pending?
	BEQ	2$			; No
	MOV	R3,-(SP)		; Yes - flush them
	MOV	(R3),R3			;Move on to next
	MOV	#MSGSIZ,R0		;AL-ARM message size
	JSR	PC,$B72			;Call DISPOSE
	BR	1$
2$:	CLR	CONHST			;No connection open now
	QIO$S	#IO.KIL,#ENIN		;Flush any pending pup reads
FIN:
	ENDPR


;Aux routine

READPU:	CMPB	#HELLOP,PUPTYP(R3)	;Someone trying to open a connection?
	BNE	10$			; No
	MOV	#BSYPUP,R1		; Yes
	JSR	PC,SETOPUP		;Set up pup
	MOV	(R3),(R1)		;Use correct address info
	SWAB	(R1)
	MOV	SRCHST(R3),DSTHST(R1)
	MOV	SRCSOC(R3),DSTSOC(R1)
	MOV	SRCSC2(R3),DSTSC2(R1)
	MOVB	#ARMBSY,BSYPUP+PUPTYP	;Say ARM is busy
	CMP	SRCHST(R3),CONHST	;Check if same as current connection
	BNE	5$			; No
	CMP	SRCSOC(R3),CONSOC
	BNE	5$			; No
	CMP	SRCSC2(R3),CONSC2
	BNE	5$			; No
	MOVB	#ARMFRE,BSYPUP+PUPTYP	;Say ARM free - must be extra HELLO pup
5$:	JSR	PC,SNDPUP		;Send reply out
	BR	99$			;  & all done
10$:	CMPB	#BYEBYE,PUPTYP(R3)	;AL going away?
	BNE	20$			; No
	TST	(SP)+			; Yes - flush return address
	MOV	#3,R1
	BR	ALDEAD			;  & quit
20$:	CMPB	#ALLIVE,PUPTYP(R3)	;Response to a THEREP pup?
	BNE	30$			; No
	CLR	THEREC			; Yes - clear time-out
	BR	98$			;  & all done
30$:	CMPB	#ACK,PUPTYP(R3)		;An ACK?
	BNE	40$			; No
	CMP	SEQOUT,PUPID(R3)	; Yes - is it for last packet sent?
	BNE	98$			;   No - a repeat
	CMP	SEQOU2,PUPID2(R3)
	BNE	98$			;   No - a repeat
	CLR	ACKTIM			;   Yes - clear ACK time-out
	BR	98$			;     & all done
40$:	CMPB	#ALARM,PUPTYP(R3)	;A message for ARM?
	BNE	99$			; No - ignore it
	MOV	#ACKPUP,R1		; Yes - send back an ACK
	JSR	PC,SETOPUP		;Set up address info
	MOVB	#ACK,ACKPUP+PUPTYP
	MOV	PUPID(R3),PUPID(R1)	;Set up sequence number
	MOV	PUPID2(R3),PUPID2(R1)
	JSR	PC,SNDPUP		;Send ACK out
	CMP	SEQIN,PUPID(R3)		;Have we seen this one yet?
	BHI	98$			; Yes - a repeat
	CMP	SEQIN2,PUPID2(R3)
	BHIS	98$			; Yes - a repeat
	MOV	PUPID(R3),SEQIN		; No - advance sequence number
	MOV	PUPID2(R3),SEQIN2
	MOV	INPMES,R1		;Get AL-ARM message record
	CLR	(R1)+			;Zero next pointer
	ADD	#PDATA,R3		;R3 = Start of AL-ARM message
	MOV	#MSGSIZ/2-1,R0		;Length in words of AL-ARM message
45$:	MOV	(R3)+,(R1)+		;Copy AL-ARM message
	SOB	R0,45$
	INC	MESREC			;Indicate we got one

98$:	INC	IOACT			;Set I/O flag
99$:	RTS	PC

;Aux routins: SETOPUP & SNDPUP

;Aux routine to setup pup header for current connection

SETOPU:	MOV	R1,-(SP)		;Save pointer to pup
	MOV	CONDST,(R1)+
	MOV	#PUP,(R1)+		;We're a pup
	MOV	#PUPOV,(R1)+		;Assume length = pup overhead only
	CLR	(R1)+			;Later need to set pup type
	CLR	(R1)+			;Likewise for pup id
	CLR	(R1)+
	MOV	CONHST,(R1)+		;Copy destination host/network
	MOV	CONSOC,(R1)+		; & destination socket
	MOV	CONSC2,(R1)+		; & destination socket
	MOV	HSTNUM,(R1)+		;Copy server host/net info
	CLR	(R1)+
	MOV	#ARMSOC,(R1)		;Set source socket = ARM server
	MOV	(SP)+,R1		;Restore pup pointer
	RTS	PC

;Aux routine to calculate pup checksum & send out pup

SNDPUP:	MOV	R0,-(SP)	;Save pointer to pup & other regs
	MOV	R2,-(SP)
	MOV	R1,-(SP)
	ADD	#4,R1		;R1 = LOC(pup+length)
	MOV	(R1),R2		;R2 = Pup length in bytes
	INC	R2		;Get word count
	ASR	R2
	DEC	R2
	CLR	R0		;Now compute checksum
1$:	ADD	(R1)+,R0	;One's complement addition
	ADC	R0
	ASL	R0		;Rotate left
	ADC	R0
	SOB	R2,1$
	CMP	R0,#177777	;Change negative zero checksum to positive zero
	BNE	2$
	CLR	R0
2$:	MOV	R0,(R1)		;Store away checksum

	MOV	(SP)+,R1	;Retrieve pointer to pup
	MOV	4(R1),R2	;R2 = Pup length in bytes
	ADD	#4,R2		;Add in overhead bytes
	QIO$S	#IO.WLB,#ENOUT,,,,,<R1,R2>	;Send out the pup packet to AL

	MOV	(SP)+,R2	;Restore regs
	MOV	(SP)+,R0
	RTS	PC

      .END